
const clickoutsideContext = '@@clickoutsideContext';

export default {
  /*
   @param el 指令所绑定的元素
   @param binding {Object} 
   @param vnode vue编译生成的虚拟节点
   */

  /*
  @param el：指令所绑定的元素，可以用来直接操作 DOM 。
  @param binding：一个对象，包含以下属性：
  @param name：指令名，不包括 v- 前缀。
  @param value：指令的绑定值，例如：v-my-directive="1 + 1" 中，绑定值为 2。
  @param oldValue：指令绑定的前一个值，仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
  @param expression：字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中，表达式为 "1 + 1"。
  @param arg：传给指令的参数，可选。例如 v-my-directive:foo 中，参数为 "foo"。
  @param modifiers：一个包含修饰符的对象。例如：v-my-directive.foo.bar 中，修饰符对象为 { foo: true, bar: true }。
  @param vnode：Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。
  @param oldVnode：上一个虚拟节点，仅在 update 和 componentUpdated 钩子中可用。
  */
  //只调用一次，指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
  bind (el, binding, vnode) {
    const documentHandler = function(e) {
      console.log(el)
      console.log(e.target);
      console.log(vnode);
      console.log(binding);
      
      if(!vnode.context || el.contains(e.target)) {
        return false;
      }
      if (binding.expression) {
        vnode.context[el[clickoutsideContext].methodName](e)
      } else {
        el[clickoutsideContext].bindingFn(e);
      }
    }
    el[clickoutsideContext] = {
      documentHandler,
      methodName: binding.expression,
      bindingFn: binding.value
    }
    setTimeout(() => {
      document.addEventListener('click', documentHandler);
    }, 0)
  },
  /*
  所在组件的 VNode 更新时调用，但是可能发生在其子 VNode 更新之前。
  指令的值可能发生了改变，也可能没有。
  但是你可以通过比较更新前后的值来忽略不必要的模板更新。
  */
  update (el, binding) {
    el[clickoutsideContext].methodName = binding.expression;
    el[clickoutsideContext].bindingFn = binding.value;
  },
  //只调用一次，指令与元素解绑时调用
  unbind(el) {
    document.removeEventListener('click', el[clickoutsideContext].documentHandler);
  }
}
